/*************************************************************************
	> File Name: PluginManager.cpp
	> Author: 
	> Mail: 
	> Created Time: 2017年05月25日 星期四 03时20分53秒
 ************************************************************************/

#include "PluginManager.h"

#include <dirent.h>
#include <dlfcn.h>
#include <string.h>
#include <algorithm>
#include <cstdio>
#include <iostream>
#include <sstream>
#include <string>
#include <utility>

#include "public/event/JuzEvent.h"
#include "public/PublicDefine.h"

using namespace std;

#define DLL_FILE_NAME "libcac.so"

PluginManager*  PluginManager::mPluginManager = NULL;

bool SortBySe(struct_event *se1,struct_event *se2)
{

	if(se1 != NULL && se2 != NULL)
	{
		return se1->mPriority >= se2->mPriority ;
	}
	else
	{
		return false;
	}
}

PluginManager::PluginManager()
{
}
void PluginManager::sendEvent(JuzEvent* event) {

	//这里只能使用cout 打印　否则死循环
	if(event == NULL) return;

    map<string, eVect*>::iterator iter;
    string findStr = event->mEventName;
    iter = mEventList.find(findStr);

    if(iter != mEventList.end())
    {
    	//找到的话 往下派发
    	eVect *eV = iter->second;
    	_JUZEVENTTYPE eventType = event->getType();

        int count = eV->size();
        for (int i = 0; i < count;i++)
        {
        	struct_event *se  = (*eV)[i];
        	if(se != NULL)
        	{

        	    map<uuid_t*,Plugin*>::iterator iterPl;
        	    iterPl = mPluginList.find(se->mUUID);
        	    if(iterPl != mPluginList.end())
        	    {
        	    	Plugin *thePlugin = iterPl->second;
        	    	thePlugin->eventListen(event);
        	    }

        	    if(eventType == _general)//如果是普通事件
        	    {
            	    if(event->getBreakoff()) //事件是否被中断了
            	    {
            	    	return ;
            	    }
            	    else if(event->getDisable())
            	    {
            	    	delete event;
            	    	return;
            	    }
        	    }
        	}
        }
    }
}

void PluginManager::registeredEvent(string eName,int priority,uuid_t *uid)
{

     map<string, eVect*>::iterator iter;
     iter = mEventList.find(eName);

     if(iter != mEventList.end())
     {
    	 eVect *eV = iter->second;
    	 if(eV != NULL)
    	 {
    		 struct_event *se = new struct_event;
        	 se->mPriority = priority;
        	 se->mUUID = uid;

    		 eV->push_back(se);
    	 }
     }
     else
     {
    	 struct_event *se = new struct_event;
    	 eVect *eV = new eVect;

    	 se->mPriority = priority;
    	 se->mUUID = uid;

    	 eV->push_back(se);

    	 //cout<<"reg event "<<event->mEventName.data()<<" num:"<<priority<<endl;
    	 mEventList.insert(pair<string,eVect*>(eName,eV));
     }

}

PluginManager* PluginManager::getInstance()
{
    if(mPluginManager == NULL)
    {
        mPluginManager = new PluginManager();
    }
    return mPluginManager;
}
int PluginManager::loadFilePlugin(const char *basePath)
{
    DIR *dir;
    struct dirent *ptr;
    char base[1024];

    if ((dir=opendir(basePath)) == NULL)
    {
        perror("打开文件夹失败！！");
        perror(basePath);
        return 0;
    }

    while ((ptr=readdir(dir)) != NULL)
    {
        if(strcmp(ptr->d_name,".")==0 || strcmp(ptr->d_name,"..")==0)    ///current dir OR parrent dir
            continue;
        else if(ptr->d_type == 8)    ///file
        {
            int nTailLen = strlen(ptr->d_name);
            if(nTailLen > 3)
            {
                char *cFileTail = &ptr->d_name[nTailLen - 3];
                if(strcmp(cFileTail,".so") == 0)
                {
                	char *fPath = new char[10 + strlen(basePath) + strlen(ptr->d_name)];
                	strcpy(fPath,basePath);
                	strcat(fPath,ptr->d_name);
                	cout<<"准备加载插件库 name = "<<fPath<<endl;
                	loadPlugin(fPath);
                	delete[] fPath;
                }
            }
        }
        else if(ptr->d_type == 4)    ///dir
        {
            memset(base,'\0',sizeof(base));
            strcpy(base,basePath);
            strcat(base,"/");
            strcat(base,ptr->d_name);
            loadFilePlugin(base);
        }
    }
    closedir(dir);
    return 1;

}

void PluginManager::loadPlugin(const char* pluginPath) {


    void *handle;
    typedef Plugin* (*loadPluginFUn)(void) ;
    loadPluginFUn func;


	handle = dlopen(pluginPath, RTLD_NOW);
	if (handle == NULL)
	{
		cout<<"读取Plugin失败!名  = "<<pluginPath<<" error:"<<dlerror()<<endl;
		return ;
	}


	func = (loadPluginFUn)dlsym(handle, "loadSoPlugin");
	bool isRead = false;

	if(func != NULL)
	{
		Plugin *pl = func();

		if(pl != NULL)
		{
			registeredPlugin(pl);
			isRead = true;
		}
	}
	else
	{
		cout<<"读取动态库函数失败! name  = "<<pluginPath<<endl;
	}

	if(!isRead) dlclose(handle);

}

void PluginManager::Init() {

	//先进行 优先级排序

	map<string,eVect*>::iterator it = mEventList.begin();
	while(it != mEventList.end())
	{
		eVect *eV = it->second;
		if(eV != NULL)
		{
			sort(eV->begin(),eV->end(),SortBySe);
		}
		it++;
	}
}

void PluginManager::registeredPlugin(Plugin *pl) {
	uuid_t *uuid = (uuid_t*)new char[sizeof(uuid_t)];
	uuid_generate( *uuid );

	pl->bindPlugin(this,uuid);
	mPluginList.insert(pair<uuid_t*,Plugin*>(uuid,pl));
}
